﻿using lumo;
using lumo.display.animation2D;
using lumo.display.gui;
using lumo.display.object2D;
using lumo.input;
using lumo.scene;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace game.scene
{

    public class SceneTitle : IScene
    {

        protected Sprite          _Background;
        protected Sprite _Title;
        protected Sprite[] _Sprites = new Sprite[4];
        protected SerialAnimation2D[] _SpritesAnimations = new SerialAnimation2D[4];
        protected string[] _SpritesTextures = new string[] { "Graphics/Title/Enemy", "Graphics/Title/Enemy", "Graphics/Title/Enemy", "Graphics/Title/BigSubmarine" };

        protected Texture2D _WaterNormal;
        protected Effect _WaterEffect;

        protected Menu                 _Menu;
        protected IAnimation2D _FadeAnimation;

        protected IScene _PreviousScene;

        public SceneTitle(IScene previousScene)
        {
            _PreviousScene = previousScene;
        }

        /// <summary>
        /// Start the scene
        /// </summary>
        /// <param name="component"></param>
        public void Start(LumoComponent component)
        {
            if (!((_PreviousScene is SceneIntro) || (_PreviousScene is SceneCredits)))
            {
                Song song = component.Content.Load<Song>("Audio/BGM/Title");
                MediaPlayer.Play(song);
            }

            _Background = new Sprite(component.Content.Load<Texture2D>("Graphics/Title/Background"));
            _Title = new Sprite(component.Content.Load<Texture2D>("Graphics/Pictures/Title"));
            _Title.Position = new Vector2(Global.DefaultScreenSize.X - _Title.Texture.Width - 64, 64);

            #region Sprites

            for (int i = 0; i < 4; i++)
            {
                _Sprites[i] = new Sprite(component.Content.Load<Texture2D>(_SpritesTextures[i]));
                _Sprites[i].X = -_Sprites[i].Texture.Width;
                _Sprites[i].Y = -_Sprites[i].Texture.Height;
                _Sprites[i].Scale = Vector2.Zero;

                Vector2 initialPosition, finalPosition;
                switch (i)
                {
                    case 0:
                        initialPosition = new Vector2(32.0f, 32.0f);
                        finalPosition = new Vector2(32.0f, 0.0f);
                        break;
                    case 1:
                        initialPosition = new Vector2(128.0f, 64.0f);
                        finalPosition = new Vector2(128.0f, 32.0f);
                        break;
                    case 2:
                        initialPosition = new Vector2(64.0f, 128.0f);
                        finalPosition = new Vector2(64.0f, 160.0f);
                        break;
                    default:
                        initialPosition = new Vector2(32.0f, Global.DefaultScreenSize.Y - _Sprites[i].Texture.Height - 32);
                        finalPosition = new Vector2(32.0f, Global.DefaultScreenSize.Y - _Sprites[i].Texture.Height - 64);
                        break;
                }

                SerialAnimation2D serialAnimation = new SerialAnimation2D(_Sprites[i]);
                    ParallelAnimation2D parallelAnimation = new ParallelAnimation2D(_Sprites[i]);
                    parallelAnimation.Add(new ScaleAnimation2D(new Vector2(1.0f / (4 - i), 1.0f / (4 - i)), 1000.0f * (4 - i), Smooth.Arrival, Loop.None));
                    parallelAnimation.Add(new PositionAnimation2D(initialPosition, 1000.0f * (4 - i), Smooth.Arrival, Loop.None));
                serialAnimation.Add(parallelAnimation);
                serialAnimation.Add(new PositionAnimation2D(finalPosition, 4000.0f, Smooth.StartArrival, Loop.ZigZag));

                _SpritesAnimations[i] = serialAnimation;
            }

            #endregion

            _WaterNormal = component.Content.Load<Texture2D>("Effects/WaterNormal");
            _WaterEffect = component.Content.Load<Effect>("Effects/Water");

            Global.CursorSprite.Texture = component.Content.Load<Texture2D>("Graphics/Cursors/Cursor");

            #region Menu

            _Menu = new Menu();

            InputWrapper confirmInputWrapper = new InputWrapper();
                confirmInputWrapper.Add(Global.Keypad.GetKey(Keys.Enter));
                confirmInputWrapper.Add(Global.Cursor.GetButton(Cursor.Button.Left));
            _Menu.Input = confirmInputWrapper;

            CustomPositionableCommandList commandList = new CustomPositionableCommandList();
                Texture2D texture;
                for (int i = 0; i < 3; i++)
                {
                    switch (i)
                    {
                        case 0:
                            texture = component.Content.Load<Texture2D>("Graphics/Pictures/Start");
                            break;
                        case 1:
                            texture = component.Content.Load<Texture2D>("Graphics/Pictures/Credits");
                            break;
                        default:
                            texture = component.Content.Load<Texture2D>("Graphics/Pictures/Exit");
                            break;
                    }
                    commandList.Add(new Sprite(texture));
                }
                commandList.Initialize(1000.0f);
            commandList.Cursor = Global.Cursor;

            InputWrapper decreaseInputWrapper = new InputWrapper();
                decreaseInputWrapper.Add(Global.Keypad.GetKey(Keys.Up));
            commandList.DecreaseIndexInput = decreaseInputWrapper;

            InputWrapper increaseInputWrapper = new InputWrapper();
                increaseInputWrapper.Add(Global.Keypad.GetKey(Keys.Down));
            commandList.IncreaseIndexInput = increaseInputWrapper;
            commandList.Initialize(100.0f);

            for (int i = 0; i < commandList.Count; i++)
                commandList.Offset[i] = new Vector2(Global.DefaultScreenSize.X - 256, Global.DefaultScreenSize.Y - commandList.Count * 128 + 96 * i);

            _Menu.CommandList = commandList;

            _Menu.OnIndex(0, Action => SetupSceneOut(component, new SceneMap()));
            _Menu.OnIndex(1, Action => SetupSceneOut(component, new SceneCredits(this)));
            _Menu.OnIndex(2, Action => SetupSceneOut(component, null));

            #endregion

            Global.Box.Color = Color.Black;
            _FadeAnimation = new ColorAnimation2D(Color.Transparent, 2000.0f, Smooth.StartArrival, Loop.None, Global.Box);
        }

        protected void SetupSceneOut(LumoComponent component, IScene nextScene)
        {
            SerialAnimation2D serialAnimation = new SerialAnimation2D(Global.Box);
            serialAnimation.Add(new ColorAnimation2D(Color.Black, 2000.0f, Smooth.StartArrival, Loop.None));
            serialAnimation.Add(new LambdaAnimation2D(SubAction => component.Scene = nextScene));
            _FadeAnimation = serialAnimation;
        }

        /// <summary>
        /// Update the scene.
        /// </summary>
        /// <param name="Component"></param>
        public void Update(LumoComponent Component)
        {
            float offset = (float)(Component.GameTime.TotalGameTime.TotalSeconds / 32.0f);
            _WaterEffect.Parameters["offsetX"].SetValue((float)(offset - System.Math.Floor(offset)));
            _WaterEffect.Parameters["offsetY"].SetValue((float)(offset - System.Math.Floor(offset)));
            _FadeAnimation.Update(Component);
            for (int i = 0; i < _SpritesAnimations.Length; i++)
                _SpritesAnimations[i].Update(Component);
            if (!(_FadeAnimation is SerialAnimation2D))
                _Menu.Update(Component);
        }

        /// <summary>
        /// Draw the scene.
        /// </summary>
        /// <param name="Component"></param>
        public void Draw(LumoComponent Component)
        {
            RenderTarget2D renderTarget = new RenderTarget2D(Component.GraphicsDevice, (int)Global.DefaultScreenSize.X, (int)Global.DefaultScreenSize.Y);
            Component.GraphicsDevice.SetRenderTarget(renderTarget);
            Component.GraphicsDevice.Clear(Color.Black);

            #region Sprites

            Component.SpriteBatch.Begin(SpriteSortMode.Immediate, null);
                _Background.Draw(Component.SpriteBatch);
                for (int i = 0; i < _Sprites.Length; i++)
                    _Sprites[i].Draw(Component.SpriteBatch);
            Component.SpriteBatch.End();

            #endregion

            Component.GraphicsDevice.SetRenderTarget(null);
            Component.GraphicsDevice.Clear(Color.Black);

            #region Water

            Component.SpriteBatch.Begin(SpriteSortMode.Immediate, null, null, null, null, _WaterEffect, Global.ScreenMatrix);
                Component.GraphicsDevice.Textures[1] = _WaterNormal;
                Component.SpriteBatch.Draw(renderTarget, Vector2.Zero, Color.White);
                Component.GraphicsDevice.Textures[1] = null;
            Component.SpriteBatch.End();

            #endregion

            #region Menu

            Component.SpriteBatch.Begin(SpriteSortMode.Immediate, null, null, null, null, null, Global.ScreenMatrix);
                _Menu.Draw(Component.SpriteBatch);
                _Title.Draw(Component.SpriteBatch);
            Component.SpriteBatch.End();

            #endregion

            #region Cursor

            Component.SpriteBatch.Begin(SpriteSortMode.Immediate, null);
                Global.CursorSprite.Draw(Component.SpriteBatch);
            Component.SpriteBatch.End();

            #endregion

            #region BoxOverlay

            Component.SpriteBatch.Begin(SpriteSortMode.Immediate, null, null, null, null, null, Global.ScreenMatrix);
                Global.Box.Draw(Component.SpriteBatch);
            Component.SpriteBatch.End();

            #endregion

            renderTarget.Dispose();
        }

        /// <summary>
        /// Terminate the scene
        /// </summary>
        /// <param name="Game"></param>
        public void Terminate(LumoComponent Component)
        {
        }

    }

}
